/**********************************************************************
*                                                                     *
*    CCCCCCCCCC  GGGGGGGGGG  VV        VV                             *
*    CC          GG           VV      VV   II   EEEEE    W       W    *
*    CC          GG            VV    VV        E     E   W       W    *
*    CC          GG    GGGG     VV  VV     II  EEEEEE    W   W   W    *
*    CC          GG      GG      VVVV      II  E         W   W   W    *
*    CCCCCCCCCC  GGGGGGGGGG       VV       II   EEEEEE    WWW WWW     *
*                                                                     *
**********************************************************************/


/*
  L'header mesh_definition viene utilizzato per creare un'interfaccia
  con la definizione di mesh della libreira VCG
*/


#ifndef MESH_DEFINITION_H
#define MESH_DEFINITION_H

#include <cstdlib>
#include <vector>
#include <string>

#include <vcg/simplex/vertex/base.h>
#include <vcg/simplex/vertex/component.h>
#include <vcg/simplex/face/base.h>
#include <vcg/simplex/face/pos.h>
#include <vcg/simplex/face/component.h>
#include <vcg/simplex/face/component_ocf.h>

#include <vcg/complex/trimesh/base.h>
#include <vcg/complex/trimesh/update/topology.h>
#include <vcg/complex/trimesh/allocate.h>


//class CGEdge;
class CGFace;
class CGVertex;

class CGTypes : public vcg::UsedTypes< vcg::Use<CGVertex>::AsVertexType, vcg::Use<CGFace>::AsFaceType/*,
    vcg::Use<CGEdge>::AsEdgeType*/ >{};

class CGVertex: public vcg::Vertex<CGTypes,
   vcg::vertex::Coord3d,
   vcg::vertex::Normal3d,
   vcg::vertex::Color4b,
   vcg::vertex::Qualityf,
   vcg::vertex::BitFlags,
   vcg::vertex::Mark,
   vcg::vertex::VFAdj> {};

class CGFace: public vcg::Face<CGTypes,
vcg::face::FFAdj,
vcg::face::Normal3d,
vcg::face::VertexRef,
vcg::face::BitFlags,
vcg::face::Mark,
vcg::vertex::Color4b,
vcg::vertex::Qualityf> {
	public:
		int edgeAdj[3];
 };

class CGEdge {

public:
	CGEdge() {};

	inline CGFace*& F0() { return f0; }
	inline CGFace*& F1() { return f1; }

	inline int& iF0() { return if0; }
	inline int& iF1() { return if1; }

	inline CGVertex*& V0() { return v0; }
	inline CGVertex*& V1() { return v1; }

	inline int& iV0() { return iv0; }
	inline int& iV1() { return iv1; }

	inline double& Q() { return quality; }
	inline double& Geod() { return geodesic; }
	inline double& DihA() { return dihedral; }
	inline int& Dens() { return density; }

	inline vcg::Color4b& C() { return color; }

private:
	CGFace* f0;
	CGFace* f1;

	int if0;
	int if1;

	CGVertex* v0;
	CGVertex* v1;

	int iv0;
	int iv1;

	double quality;
	double geodesic;
	double dihedral;
	int    density;

	vcg::Color4b color;

};

class CGMesh : public vcg::tri::TriMesh<
   std::vector<CGVertex>, std::vector<CGFace> > { 

public:
	std::vector<CGEdge> edges;

	void initEdges(void) {
		//space reserve
		edges.resize(3 * this->face.size());
		//update topology
		vcg::tri::UpdateTopology<CGMesh>::FaceFace(*this);
		//clean mark flags
		vcg::tri::UnMarkAll(*this);

		int edgecnt = 0;
		//loop on the faces
		for ( CGMesh::FaceIterator fit = this->face.begin(); fit != this->face.end(); ++ fit ) {
			
			//loop around the neighbors
			for ( int i = 0; i < 3; i ++ ) {
				if ( vcg::tri::IsMarked( *this, (*fit).FFp(i) ) ) continue;	//already visited
				//...not visited! 
				//Faces information
				edges[edgecnt].F0() = &(*fit);
				edges[edgecnt].F1() = (*fit).FFp(i);
				edges[edgecnt].iF0() = vcg::tri::Index( *this, &(*fit) );
				edges[edgecnt].iF1() = vcg::tri::Index( *this, (*fit).FFp(i) );
				//Vertex information
				edges[edgecnt].V0() = (*fit).V(i);
				edges[edgecnt].V1() = (*fit).V1(i);
				edges[edgecnt].iV0() = vcg::tri::Index( *this, (*fit).V(i)  );
				edges[edgecnt].iV1() = vcg::tri::Index( *this, (*fit).V1(i) );
				//update reference to the faces
				(*fit).edgeAdj[i] = edgecnt;
				(*fit).FFp(i)->edgeAdj[(*fit).FFi(i)] = edgecnt; 
	 			//set values
				edges[edgecnt].Q() = 0.0;
				edges[edgecnt].Dens() = 0;
				edges[edgecnt].C() = vcg::Color4b::Black;
				//increment counter
				edgecnt++;
			}

			//mark the face as visited
			vcg::tri::Mark( *this, &(*fit) );
		}

		edges.resize(edgecnt);
	}

	std::string getName(void)   { return name; }
	void setName(std::string n) { name = n; }

private:
	std::string name;
};

typedef CGMesh::CoordType CGPoint;

#endif // MESH_DEFINITION_H
